package dao;

import helper.DateTimeHelper;
import helper.StringHelper;

import java.sql.ResultSet;
import java.util.ArrayList;

import util.Config;

import model.WeatherModel;
import model.WindModel;

/**
 * DB-Lesezugriffe auf WeatherModel
 * 
 * @author Katharina Matei
 * @version 1.0.0
 */

public class WeatherDAO implements WeatherDAOInterface {

	/**
	 * Liest das aktuelle Wetter in City aus der DB
	 * 
	 * @param String cityID
	 * @return WeatherModel
	 * @throws DBException
	 */
	@Override
	public WeatherModel getAktWeatherByCity(String cityID) throws DBException {
		WeatherModel weather = null;
		String dbStatement = "SELECT * FROM weathermodel where city_id = '"
				+ StringHelper.addSlashes(cityID) + "' ORDER BY id DESC ";
		try {
			ResultSet resultSet = DBAccess.getInstance().query(dbStatement);
			while (resultSet.next()) {
				weather = new WeatherModel();
				weather.setCityID(resultSet.getString("city_id"));
				weather.setInfo(resultSet.getString("info"));
				weather.setTemperature(resultSet.getDouble("temperature"));
				weather.setWindDirectionInfo(resultSet
						.getString("wind_direction"));
				weather.setObservationTime(resultSet.getString("observ_time"));
				weather.setTimeStamp(resultSet.getLong("tstamp"));
				weather.setDate(resultSet.getString("date_timestamp"));
				weather.setVisibility(resultSet.getInt("visibility"));
				weather.setAirPressure(resultSet.getDouble("pressure"));
				weather.setCloudiness(resultSet.getString("clouds"));
				populateWithWindModel(weather);
				weather.getWind().setDirection(resultSet.getInt("wind_deg"));
				weather.getWind().setSpeedKnot(resultSet.getInt("wind_speed"));
				break;
			}
		} catch (Exception e) {
			if (Config.DEBUG) {
				e.printStackTrace();
			}
			throw new DBException("Fehler in : " + dbStatement, e);
		}
		return weather;
	}

	/**
	 * Liest alle Wetter-Daten aus der DB
	 * 
	 * @return ArrayList<WeatherModel>
	 * @throws DBException
	 */
	@Override
	public ArrayList<WeatherModel> getWeatherModelAll() throws DBException {
		String dbStatement = "SELECT * FROM weathermodel";
		return getDBDaten(dbStatement);
	}

	/**
	 * Liest die Wetter-Daten in City fuer Zeitinterval (von-bis) aus der DB
	 * 
	 * @param String cityID, String von, String bis
	 * @return ArrayList<WeatherModel>
	 * @throws DBException
	 */
	@Override
	public ArrayList<WeatherModel> getWeatherVonBis(String cityID, String von,
			String bis) throws DBException {
		String dbStatement = "SELECT * from weathermodel WHERE city_id = '"
				+ StringHelper.addSlashes(cityID) + "' and date_timestamp >= '"
				+ StringHelper.addSlashes(von) + "' and date_timestamp <= '"
				+ StringHelper.addSlashes(bis) + "'";
		return getDBDaten(dbStatement);
	}

	/**
	 * Fuegt die Wetter-Daten in die DB ein
	 * 
	 * @param WeatherModel
	 * @throws DBException
	 */
	@Override
	public void insert(WeatherModel wm) throws DBException {
		checkBeforeInsert(wm);
		int direction = 0;
		double speedKnot = 0;
		if (wm.getWind() != null) {
			direction = wm.getWind().getDirection();
			speedKnot = wm.getWind().getSpeedKnot();
		}
		String dbStatement = "INSERT INTO weathermodel (city_id, info, temperature, wind_direction, wind_deg, wind_speed, observ_time,"
				+ " tstamp, date_timestamp, visibility, pressure, clouds) VALUES ('"
				+ wm.getCityID()
				+ "','"
				+ wm.getInfo()
				+ "', "
				+ wm.getTemperature()
				+ " ,'"
				+ wm.getWindDirectionInfo()
				+ "', "
				+ direction
				+ ", "
				+ speedKnot
				+ ",'"
				+ wm.getObservationTime()
				+ "', "
				+ wm.getTimeStamp()
				+ " ,'"
				+ wm.getDate()
				+ "', "
				+ wm.getVisibility()
				+ " , "
				+ wm.getAirPressure() + " ,'" + wm.getCloudiness() + "' )";
		executeDBStatement(dbStatement);
	}

	/**
	 * Liest alle Wetter-Daten in City aus der DB
	 * 
	 * @param String cityID
	 * @return ArrayList<WeatherModel>
	 * @throws DBException
	 */
	@Override
	public ArrayList<WeatherModel> getAllWeatherByCity(String cityID)
			throws DBException {
		String dbStatement = "SELECT * FROM weathermodel where city_id = '"
				+ StringHelper.addSlashes(cityID) + "' ";
		return getDBDaten(dbStatement);
	}

	/**
	 * Loeschen der Wetterdaten aus der Datenbank aelter als der uebergebene
	 * Timestamp
	 * 
	 * @param String timestamp
	 * @throws DBException
	 */
	@Override
	public void delete(String timestamp) throws DBException {
		String dbStatement = "DELETE FROM weathermodel WHERE date_timestamp <= '"
				+ StringHelper.addSlashes(timestamp) + "'";
		executeDBStatement(dbStatement);
	}

	/**
	 * Erzeugt ein Wind-Objekt fuer Wetter-Daten
	 * 
	 * @param WeatherModel
	 */
	public static void populateWithWindModel(WeatherModel model) {
		model.setWind(new WindModel(model.getWindDirectionInfo()));
	}

	/**
	 * Fuehrt die DB-Anweisung aus
	 * @param dbStatement
	 * @throws DBException
	 */
	private void executeDBStatement(String dbStatement) throws DBException {
		try {
			DBAccess.getInstance().execute(dbStatement);
		} catch (Exception e) {
			if (Config.DEBUG) {
				e.printStackTrace();
			}
			throw new DBException("Fehler in : " + dbStatement, e);
		}
	}

	/**
	 * Fuellt ArrayList mit Daten aus der DB
	 * 
	 * @param String dbStatement
	 * @return ArrayList<WeatherModel>
	 * @throws DBException
	 */
	private ArrayList<WeatherModel> getDBDaten(String dbStatement)
			throws DBException {
		ArrayList<WeatherModel> list = null;
		try {
			ResultSet resultSet = DBAccess.getInstance().query(dbStatement);
			int columns = resultSet.getMetaData().getColumnCount();
			list = new ArrayList<WeatherModel>(columns);
			while (resultSet.next()) {
				WeatherModel weather = new WeatherModel();
				weather.setCityID(resultSet.getString("city_id"));
				weather.setInfo(resultSet.getString("info"));
				weather.setTemperature(resultSet.getDouble("temperature"));
				weather.setWindDirectionInfo(resultSet
						.getString("wind_direction"));
				weather.setObservationTime(resultSet.getString("observ_time"));
				weather.setTimeStamp(resultSet.getLong("tstamp"));
				weather.setDate(resultSet.getString("date_timestamp"));
				weather.setVisibility(resultSet.getInt("visibility"));
				weather.setAirPressure(resultSet.getDouble("pressure"));
				weather.setCloudiness(resultSet.getString("clouds"));
				populateWithWindModel(weather);
				weather.getWind().setDirection(resultSet.getInt("wind_deg"));
				weather.getWind().setSpeedKnot(resultSet.getInt("wind_speed"));
				list.add(weather);
			}
		} catch (Exception e) {
			if (Config.DEBUG) {
				e.printStackTrace();
			}
			throw new DBException("Fehler in : " + dbStatement, e);
		}
		return list;
	}

	/**
	 * Check vor dem Insert
	 * 
	 * @param WeatherModel
	 */
	private void checkBeforeInsert(WeatherModel wm) {
		// Pruefe, ob Timestamp richtig ist
		long timestamp = DateTimeHelper.convertToLong(wm.getDate());
		if (timestamp != wm.getTimeStamp()) {
			System.out.println("Konvertiere Timestamp: ist = "
					+ wm.getTimeStamp() + " -> soll = " + timestamp);
			wm.setTimeStamp(DateTimeHelper.convertToLong(wm.getDate()));
		}
		// Konvertiere in Derby-Timestamp-Format
		if (wm.getDate().contains("/")) {
			wm.setDate(DateTimeHelper.convertMetarDateToDerbyFormat(wm
					.getDate()));
		}
	}
}
